home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / ABUSESRC.ZIP / AbuseSrc / abuse / src / objects.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  37.4 KB  |  1,636 lines

  1. #include "timage.hpp"
  2. #include "objects.hpp"
  3. #include "chars.hpp"
  4.  
  5. #include "game.hpp"
  6. #include "intsect.hpp"
  7. #include "ability.hpp"
  8. #include "lisp.hpp"
  9. #include "jrand.hpp"
  10. #include "light.hpp"
  11. #include "dprint.hpp"
  12. #include "clisp.hpp"
  13. #include "lisp_gc.hpp"
  14. #include "profile.hpp"
  15.  
  16. #ifdef SCADALISP
  17. #define LCAR(x)        CAR(x)
  18. #define LCDR(x)        CDR(x)
  19. #else
  20. #define LCAR(x)        (x)->car
  21. #define LCDR(x)        (x)->cdr
  22. #endif /* SCADALISP */
  23.  
  24. char **object_names;
  25. int total_objects;
  26. game_object *current_object;
  27. view *current_view;
  28.  
  29. game_object *game_object::copy()
  30. {
  31.   game_object *o=create(otype,x,y);
  32.   o->state=state;
  33.   int i=0;
  34.   for (;i<TOTAL_OBJECT_VARS;i++)
  35.     o->set_var(i,get_var(i));
  36.   memcpy(o->lvars,lvars,4*figures[otype]->tv);
  37.   for (i=0;i<total_objects();i++)
  38.     o->add_object(get_object(i));
  39.   for (i=0;i<total_lights();i++)
  40.     o->add_light(get_light(i));
  41.   return o;
  42. }
  43.  
  44. int simple_object::total_vars() { return TOTAL_OBJECT_VARS; }
  45.  
  46.  
  47. obj_desc object_descriptions[TOTAL_OBJECT_VARS]={
  48.                 {"fade_dir",      RC_C },
  49.                 {"frame_dir",     RC_C },
  50.                 {"direction",     RC_C },
  51.                 {"gravity_on",    RC_C },
  52.                 {"fade_count",    RC_C },
  53.  
  54.                 {"fade_max",      RC_C },
  55.                 {"active",        RC_C },
  56.                 {"flags",         RC_C },
  57.                 {"aitype",        RC_C },
  58.                 {"xvel",          RC_L },
  59.  
  60.                 {"fxvel",         RC_C },
  61.                 {"yvel",          RC_L },
  62.                 {"fyvel",         RC_C },
  63.                 {"xacel",         RC_L },
  64.                 {"fxacel",        RC_C },
  65.  
  66.                 {"yacel",         RC_L },
  67.                 {"fyacel",        RC_C },
  68.                 {"x",             RC_L },
  69.                 {"fx",            RC_C },
  70.                 {"y",             RC_L },
  71.  
  72.                 {"fy",            RC_C },
  73.                 {"hp",            RC_S },
  74.                 {"mp",            RC_S },
  75.                 {"fmp",           RC_S },
  76.                 {"cur_frame",     RC_S },
  77.  
  78.                 {"aistate",       RC_S },
  79.                 {"aistate_time",  RC_S },
  80.                 {"targetable",    RC_C }
  81.  
  82.                   };
  83.   
  84. long game_object::get_var_by_name(char *name, int &error)
  85. {
  86.   error=0;
  87.   int i=0;
  88.   for (;i<TOTAL_OBJECT_VARS;i++)
  89.   {
  90.     if (!strcmp(object_descriptions[i].name,name))
  91.       return get_var(i);
  92.   }
  93.  
  94.   for (i=0;i<figures[otype]->tiv;i++)
  95.   {
  96.     if (!strcmp(lstring_value(symbol_name(figures[otype]->vars[i])),name))
  97.     {
  98.       return lvars[figures[otype]->var_index[i]];
  99. /*      lisp_object_var *cobj=(lisp_object_var *)symbol_value(figures[otype]->vars[i]);
  100.       character_type *t=figures[otype];
  101.       int number=cobj->number;
  102.       if (t->tiv<=number || !t->vars[number])
  103.       {
  104.     lbreak("access : variable does not exsist for this class\n");
  105.     return 0;
  106.       }
  107.       return lvars[t->var_index[number]];*/
  108.     }
  109.   }
  110.   error=1;
  111.   return 0;
  112. }
  113.  
  114. int game_object::set_var_by_name(char *name, long value)
  115. {
  116.   int i=0;
  117.   for (;i<TOTAL_OBJECT_VARS;i++)
  118.   {
  119.     if (!strcmp(object_descriptions[i].name,name))
  120.     {
  121.       set_var(i,value);
  122.       return 1;
  123.     }
  124.   }
  125.   for (i=0;i<figures[otype]->tiv;i++)
  126.     if (!strcmp(lstring_value(symbol_name(figures[otype]->vars[i])),name))
  127.     {
  128.       lvars[figures[otype]->var_index[i]]=value;
  129.       return 1;
  130.     }
  131.   return 0;
  132. }
  133.  
  134.  
  135. char *simple_object::var_name(int x)
  136. {
  137.   return object_descriptions[x].name;
  138. }
  139.  
  140. int simple_object::var_type(int x)
  141. {
  142.   return object_descriptions[x].type;
  143. }
  144.  
  145.  
  146. void simple_object::set_var(int xx, ulong v)
  147. {
  148.   switch (xx)
  149.   {
  150.     case 0 : set_fade_dir(v); break;
  151.     case 1 : set_frame_dir(v); break;
  152.     case 2 : direction=v; break;
  153.     case 3 : set_gravity(v); break;
  154.     case 4 : set_fade_count(v); break;
  155.     case 5 : set_fade_max(v); break;
  156.     case 6 : active=v;break;
  157.     case 7 : set_flags(v); break;
  158.     case 8 : set_aitype(v); break;
  159.     case 9 : set_xvel(v); break;
  160.  
  161.     case 10 : set_fxvel(v); break;
  162.     case 11 : set_yvel(v); break;
  163.     case 12 : set_fyvel(v); break;
  164.     case 13 : set_xacel(v); break;
  165.     case 14 : set_fxacel(v); break;
  166.  
  167.     case 15 : set_yacel(v); break;
  168.     case 16 : set_fyacel(v); break;
  169.     case 17 : x=v; break;
  170.     case 18 : set_fx(v); break;
  171.     case 19 : y=v; break;
  172.  
  173.     case 20 : set_fy(v); break;
  174.     case 21 : set_hp(v); break;
  175.     case 22 : set_mp(v); break;
  176.     case 23 : set_fmp(v); break;
  177.  
  178.     case 24 : current_frame=v;  break;
  179.     case 25 : set_aistate(v); break;
  180.  
  181.     case 26 : set_aistate_time(v); break;
  182.     case 27 : set_targetable(v); break;
  183.   }
  184. }
  185.  
  186. long simple_object::get_var(int xx)
  187. {
  188.   switch (xx)
  189.   {
  190.     case 0 : return fade_dir(); break;
  191.     case 1 : return frame_dir(); break;
  192.     case 2 : return direction; break;
  193.     case 3 : return gravity(); break;
  194.     case 4 : return fade_count(); break;
  195.     case 5 : return fade_max(); break;
  196.     case 6 : return active; break;
  197.     case 7 : return flags(); break;
  198.     case 8 : return aitype(); break;
  199.     case 9 : return xvel(); break;
  200.     case 10 : return fxvel(); break;
  201.  
  202.     case 11 : return yvel(); break;
  203.     case 12 : return fyvel(); break;
  204.  
  205.     case 13 : return xacel(); break;
  206.     case 14 : return fxacel(); break;
  207.  
  208.     case 15 : return yacel(); break;
  209.     case 16 : return fyacel(); break;
  210.  
  211.     case 17 : return x; break;
  212.     case 18 : return fx(); break;
  213.  
  214.     case 19 : return y; break;
  215.     case 20 : return fy(); break;
  216.  
  217.     case 21 : return hp(); break;
  218.     case 22 : return mp(); break;
  219.     case 23 : return fmp(); break;
  220.  
  221.     case 24 : return current_frame;  break;
  222.     case 25 : return aistate(); break;
  223.     case 26 : return aistate_time(); break;
  224.     case 27 : return targetable();
  225.   }
  226.   return 0;
  227. }
  228.  
  229.  
  230.  
  231.  
  232. int RC_type_size(int type)
  233. {
  234.   switch (type)
  235.   {
  236.     case RC_C : 
  237.     { return 1; } break;
  238.     case RC_S : 
  239.     { return 2; } break;
  240.     case RC_L : 
  241.     { return 4; } break;
  242.   }        
  243.   CHECK(0);
  244.   return 1;
  245.  
  246. void game_object::reload_notify()
  247. {
  248.   void *ns=figures[otype]->get_fun(OFUN_RELOAD);  
  249.   if (ns)
  250.   {
  251.     game_object *o=current_object;
  252.     current_object=this;
  253.  
  254.     void *m=mark_heap(TMP_SPACE);
  255.     eval_function((lisp_symbol *)ns,NULL);
  256.     restore_heap(m,TMP_SPACE);
  257.  
  258.     current_object=o;
  259.   }
  260. }
  261.  
  262. void game_object::next_sequence()
  263. {
  264.   void *ns=figures[otype]->get_fun(OFUN_NEXT_STATE);
  265.   if (ns)
  266.   {  
  267.     current_object=this;
  268.     void *m=mark_heap(TMP_SPACE);
  269.     void *ret=eval_function((lisp_symbol *)ns,NULL);
  270.     restore_heap(m,TMP_SPACE);
  271.   } else
  272.   {
  273.     switch (state)
  274.     {
  275.       case dieing : 
  276.       { set_state(dead); } break;
  277.  
  278.       case end_run_jump :
  279.       {
  280.     set_state(running);
  281.       } break;
  282.       case dead :
  283.       case run_jump :
  284.       case run_jump_fall :
  285.       case running :
  286.       { set_state(state); } break;
  287.       case start_run_jump :
  288.       { 
  289.     set_yvel(get_ability(type(),jump_yvel));
  290.     if (xvel()>0)
  291.         set_xvel(get_ability(type(),jump_xvel));
  292.     else if (xvel()<0)
  293.         set_xvel(-get_ability(type(),jump_xvel));
  294.     set_xacel(0);
  295.     set_fxacel(0);
  296.     set_gravity(1);      
  297.     set_state(run_jump);
  298.       } break;
  299.  
  300.       case flinch_up :
  301.       case flinch_down :
  302.       {
  303.     if (gravity())
  304.     {
  305.       if (has_sequence(end_run_jump))
  306.         set_state(end_run_jump);
  307.       else set_state(stopped);
  308.     } else set_state(stopped);
  309.       } break;
  310.  
  311.       
  312.       default :
  313.       { set_state(stopped); } break;
  314.     }
  315.   }
  316.  
  317. }
  318.  
  319.  
  320.  
  321. game_object::~game_object()
  322. {
  323.   if (lvars) jfree(lvars);
  324.   clean_up();
  325. }
  326.  
  327. void game_object::add_power(int amount)  
  328.   int max_power=lnumber_value(symbol_value(l_max_power));  
  329.   int n=mp()+amount;
  330.   if (n<0) n=0;
  331.   if (n>max_power) n=max_power;
  332.   set_mp(n);
  333. }
  334.  
  335. void game_object::add_hp(int amount)
  336. {
  337.   if (controller() && controller()->god) return ;
  338.   int max_hp=lnumber_value(symbol_value(l_max_hp));  
  339.   int n=hp()+amount;
  340.   if (n<0) n=0;
  341.   if (n>max_hp)
  342.     n=max_hp;
  343.   set_hp(n);
  344. }
  345.  
  346. int game_object::can_morph_into(int type)
  347. {
  348.   if (type!=otype && mp()>=figures[type]->morph_power)
  349.     return 1;
  350.   else return 0;
  351. }
  352.  
  353. void game_object::morph_into(int type, void (*stat_fun)(int), int anneal, int frames)
  354. {
  355.   set_morph_status(new morph_char(this,type,stat_fun,anneal,frames));
  356.   otype=type;
  357.   set_state(stopped);
  358. }
  359.  
  360. void game_object::draw_above(view *v)
  361. {
  362.   long x1,y1,x2,y2,sy1,sy2,sx,i;
  363.   picture_space(x1,y1,x2,y2);    
  364.  
  365.   the_game->game_to_mouse(x1,y1,v,sx,sy2);
  366.   if (sy2>=v->cy1)
  367.   {
  368.     long draw_to=y1-(sy2-v->cy1),tmp=x;
  369.     current_level->foreground_intersect(x,y1,tmp,draw_to);     
  370.     the_game->game_to_mouse(x1,draw_to,v,i,sy1);     // calculate sy1
  371.  
  372.     sy1=max(v->cy1,sy1);
  373.     sy2=min(v->cy2,sy2);
  374.     trans_image *p=picture();
  375.     
  376.     for (i=sy1;i<=sy2;i++)
  377.       p->put_scan_line(screen,sx,i,0);  
  378.   }  
  379. }
  380.  
  381. int game_object::push_range()
  382. {
  383.   return get_ability(otype,push_xrange);
  384. }
  385.  
  386. int game_object::decide()
  387. {
  388.   if (figures[otype]->get_fun(OFUN_AI))
  389.   {
  390.     int old_aistate;
  391.     old_aistate=aistate();
  392.  
  393.     current_object=this;
  394.     void *m=mark_heap(TMP_SPACE);
  395.  
  396.     time_marker *prof1;
  397.     if (profiling())
  398.       prof1=new time_marker;
  399.  
  400.     Cell *ret=(Cell *)eval_function((lisp_symbol *)figures[otype]->get_fun(OFUN_AI),NULL);
  401.     if (profiling())
  402.     {
  403.       time_marker now;
  404.       profile_add_time(this->otype,now.diff_time(prof1));
  405.       delete prof1;
  406.     }
  407.  
  408.     restore_heap(m,TMP_SPACE);
  409.  
  410.     if (keep_ai_info())
  411.     {
  412.       if (aistate()!=old_aistate)
  413.       set_aistate_time(0);
  414.       else set_aistate_time(aistate_time()+1);    
  415.     }
  416.     if (!NILP(ret)) return 1;
  417.     else return 0;
  418.   }
  419.   else move(0,0,0);
  420.   return 1;
  421. }
  422.  
  423. int game_object::can_hurt(game_object *who)     // collision checking will ask first to see if you
  424. {
  425.   int is_attacker=current_level->is_attacker(this);  
  426.   // it's you against them!  Damage only if it you are attacking or they are attacking you
  427.   // I.E. don't let them hurt themselves, this can change if you over-ride this virtual function
  428.  
  429.   if (who->hurtable() && (is_attacker || current_level->is_attacker(who) || hurt_all()))
  430.     return 1;
  431.   else return 0;  
  432. }
  433.  
  434. void game_object::note_attack(game_object *whom)
  435. {
  436.   return ;   // nevermind
  437. }
  438.  
  439. void game_object::do_flinch(game_object *from)
  440. {
  441.   if (jrandom(2) && has_sequence(flinch_down))
  442.     set_state(flinch_down);
  443.   else if (has_sequence(flinch_up))
  444.     set_state(flinch_up);
  445. }
  446.  
  447.    
  448. void game_object::do_damage(int amount, game_object *from, long hitx, long hity, 
  449.                 long push_xvel, long push_yvel) 
  450. {
  451.  
  452.   void *d=figures[otype]->get_fun(OFUN_DAMAGE);  
  453.   if (d)
  454.   {
  455.     void    *am, *frm, *hx, *hy, *px, *py;  
  456.     game_object *o=current_object;
  457.     current_object=this;
  458.  
  459.     void *m=mark_heap(TMP_SPACE);
  460.  
  461.     am=new_cons_cell();
  462.     l_ptr_stack.push(&am);
  463.  
  464.     ((cons_cell *)am)->car=new_lisp_number(amount);   
  465.  
  466.     frm=new_cons_cell();
  467.     l_ptr_stack.push(&frm);
  468.  
  469.     ((cons_cell *)frm)->car=new_lisp_pointer(from);
  470.  
  471.     hx=new_cons_cell();
  472.     l_ptr_stack.push(&hx);
  473.  
  474.     ((cons_cell *)hx)->car=new_lisp_number(hitx);
  475.  
  476.     hy=new_cons_cell();
  477.     l_ptr_stack.push(&hy);
  478.     ((cons_cell *)hy)->car=new_lisp_number(hity);
  479.  
  480.     px=new_cons_cell();
  481.     l_ptr_stack.push(&px);
  482.     ((cons_cell *)px)->car=new_lisp_number(push_xvel);
  483.  
  484.     py=new_cons_cell();
  485.     l_ptr_stack.push(&py);
  486.     ((cons_cell *)py)->car=new_lisp_number(push_yvel);
  487.  
  488.  
  489.     ((cons_cell *)am)->cdr=frm;
  490.     ((cons_cell *)frm)->cdr=hx;
  491.     ((cons_cell *)hx)->cdr=hy;
  492.     ((cons_cell *)hy)->cdr=px;
  493.     ((cons_cell *)px)->cdr=py;
  494.  
  495.     time_marker *prof1;
  496.     if (profiling())
  497.       prof1=new time_marker;
  498.  
  499.     eval_user_fun((lisp_symbol *)d,am);
  500.     if (profiling())
  501.     {
  502.       time_marker now;
  503.       profile_add_time(this->otype,now.diff_time(prof1));
  504.       delete prof1;
  505.     }
  506.  
  507.  
  508.     l_ptr_stack.pop(6);
  509.    
  510.     restore_heap(m,TMP_SPACE);
  511.  
  512.     current_object=o;
  513.   } else damage_fun(amount,from,hitx,hity,push_xvel,push_yvel);
  514. #ifdef SCADALISP
  515.   ENDLOCAL();
  516. #endif
  517. }
  518.  
  519. void game_object::damage_fun(int amount, game_object *from, long hitx, long hity, 
  520.                 long push_xvel, long push_yvel) 
  521.   if (!hurtable() || !alive()) return ;
  522.  
  523.   add_hp(-amount);
  524.   set_flags(flags()|FLAG_JUST_HIT);
  525.   do_flinch(from);
  526.  
  527.   
  528.   set_xvel(xvel()+push_xvel);
  529.   if (push_yvel<0 && !gravity())
  530.     set_gravity(1);
  531.   set_yvel(yvel()+push_yvel);
  532.  
  533.   view *c=controller();
  534.   if (c && hp()<=0)
  535.   {
  536.     view *v=from->controller();
  537.     if (v) v->kills++;                       // attack from another player?
  538.     else if (from->total_objects()>0)
  539.     {
  540.       v=from->get_object(0)->controller();   // weapon from another player?
  541.       if (v && v!=c) v->kills++;
  542.       else
  543.       {
  544.     v=c;                                 // sucide
  545.     if (v) v->kills--;
  546.       }
  547.     }
  548.   }
  549. }
  550.      
  551.  
  552.  
  553. int game_object::facing_attacker(int attackerx)
  554.   return ((attackerx<x && direction<0) || (attackerx>=x && direction>0)); 
  555.  
  556. }
  557.  
  558.  
  559. void game_object::picture_space(long &x1, long &y1,long &x2, long &y2)
  560. {
  561.   int xc=x_center(),w=picture()->width(),h=picture()->height();  
  562.   if (direction>0)
  563.     x1=x-xc;  
  564.   else x1=x-(w-xc-1);  
  565.   x2=x1+w-1;
  566.   y1=y-h+1;
  567.   y2=y;  
  568. }
  569.  
  570.  
  571. int game_object::next_picture()
  572. {
  573.   int ret=1;
  574.   if (frame_dir()>0)
  575.   {
  576.     if (!current_sequence()->next_frame(current_frame))
  577.     {
  578.       next_sequence();
  579.       ret=0;
  580.     }
  581.   }
  582.   else 
  583.   {
  584.     if (!current_sequence()->last_frame(current_frame))
  585.     {
  586.       next_sequence();
  587.       ret=0;
  588.     }
  589.   }
  590.   frame_advance();
  591.   return ret;
  592. }
  593.  
  594.  
  595. long game_object::x_center()
  596. {
  597.   return current_sequence()->x_center(current_frame);   
  598. }
  599.  
  600.  
  601. void game_object::draw()
  602. {
  603.   if (figures[otype]->get_fun(OFUN_DRAW))
  604.   {
  605.     current_object=this;
  606.  
  607.     void *m=mark_heap(TMP_SPACE);
  608.     time_marker *prof1;
  609.     if (profiling())
  610.       prof1=new time_marker;
  611.  
  612.     eval_function((lisp_symbol *)figures[otype]->get_fun(OFUN_DRAW),NULL);
  613.     if (profiling())
  614.     {
  615.       time_marker now;
  616.       profile_add_time(this->otype,now.diff_time(prof1));
  617.       delete prof1;
  618.     }
  619.  
  620.  
  621.  
  622.     restore_heap(m,TMP_SPACE);
  623.  
  624.   } else drawer();
  625. }
  626.  
  627.  
  628. void game_object::map_draw()
  629. {
  630.   if (figures[otype]->get_fun(OFUN_MAP_DRAW))
  631.   {
  632.     current_object=this;
  633.  
  634.     void *m=mark_heap(TMP_SPACE);
  635.     time_marker *prof1;
  636.     if (profiling())
  637.       prof1=new time_marker;
  638.  
  639.     eval_function((lisp_symbol *)figures[otype]->get_fun(OFUN_MAP_DRAW),NULL);
  640.     if (profiling())
  641.     {
  642.       time_marker now;
  643.       profile_add_time(this->otype,now.diff_time(prof1));
  644.       delete prof1;
  645.     }
  646.  
  647.     restore_heap(m,TMP_SPACE);
  648.  
  649.   }
  650. }
  651.  
  652. void game_object::draw_trans(int count, int max)
  653. {
  654.   trans_image *cpict=picture();
  655.   cpict->put_fade(screen,
  656.           (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  657.           y-cpict->height()+1-current_vyadd,
  658.           count,max,
  659.           color_table,the_game->current_palette());
  660. }
  661.  
  662.  
  663. void game_object::draw_tint(int tint_id)
  664. {
  665.   trans_image *cpict=picture();
  666.   if (fade_count())      
  667.     cpict->put_fade_tint(screen,
  668.                (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  669.                y-cpict->height()+1-current_vyadd,
  670.                fade_count(),fade_max(),
  671.                cash.ctint(tint_id)->data,
  672.                color_table,the_game->current_palette());
  673.  
  674.  
  675.   else
  676.     cpict->put_remaped(screen,
  677.                (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  678.                y-cpict->height()+1-current_vyadd,
  679.                cash.ctint(tint_id)->data);
  680. }
  681.  
  682.  
  683. void game_object::draw_double_tint(int tint_id, int tint2)
  684. {
  685.   trans_image *cpict=picture();
  686.   if (fade_count())      
  687.     cpict->put_fade_tint(screen,
  688.                (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  689.                y-cpict->height()+1-current_vyadd,
  690.                fade_count(),fade_max(),
  691.                cash.ctint(tint_id)->data,
  692.                color_table,the_game->current_palette());
  693.  
  694.  
  695.   else
  696.     cpict->put_double_remaped(screen,
  697.                (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  698.                y-cpict->height()+1-current_vyadd,
  699.                cash.ctint(tint_id)->data,
  700.                cash.ctint(tint2)->data);
  701. }
  702.  
  703.  
  704.  
  705. void game_object::draw_predator()
  706. {
  707.   trans_image *cpict=picture();
  708.   cpict->put_predator(screen,
  709.              (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  710.              y-cpict->height()+1-current_vyadd);
  711.             
  712. }
  713.  
  714. void game_object::drawer()
  715. {
  716.   trans_image *cpict;
  717.  
  718.   if (morph_status())
  719.   {
  720.     morph_status()->draw(this,current_view);
  721.     if (morph_status()->frames_left()<1)
  722.       set_morph_status(NULL);
  723.   }
  724.   else
  725.   {
  726.     view *v=controller();
  727.  
  728.     if (fade_count())      
  729.       draw_trans(fade_count(),fade_max());
  730.     else
  731.     {
  732.       trans_image *cpict=picture();
  733.       cpict->put_image(screen,
  734.                (direction<0 ? x-(cpict->width()-x_center()-1) : x-x_center())-current_vxadd,
  735.                y-cpict->height()+1-current_vyadd);
  736.     }
  737.   }
  738. }
  739.  
  740. game_object *game_object::try_move(long x, long y, long &xv, long &yv, int checks)
  741. {
  742.   if (xv || yv)  // make sure they are suggesting movement
  743.   {    
  744.     game_object *who1=NULL,*who2=NULL;      // who did we intersect?  
  745.     long x2,y2,h;  
  746.  
  747.     if (checks&1)
  748.     {      
  749.       x2=x+xv;
  750.       y2=y+yv;    
  751.       current_level->foreground_intersect(x,y,x2,y2);
  752.       if (!stoppable())
  753.         who1=current_level->boundary_setback(this,x,y,x2,y2);
  754.       else
  755.         who1=current_level->all_boundary_setback(this,x,y,x2,y2);  
  756.       xv=x2-x;
  757.       yv=y2-y;
  758.     }
  759.     
  760.  
  761.     if (checks&2)
  762.     {      
  763.       h=picture()->height();    
  764.       x2=x+xv;    
  765.       y2=y-h+1+yv; 
  766.       current_level->foreground_intersect(x,y-h+1,x2,y2);
  767.       if (!stoppable())
  768.         who2=current_level->all_boundary_setback(this,x,y-h+1,x2,y2);    
  769.       else
  770.         who2=current_level->boundary_setback(this,x,y-h+1,x2,y2);
  771.       xv=x2-x;
  772.       yv=y2-y+h-1;  
  773.     }
  774.         
  775.     if (who2) return who2;
  776.     else return who1;
  777.   }
  778.   else return NULL;  
  779. }
  780.  
  781. void *game_object::float_tick()  // returns 1 if you hit something, 0 otherwise
  782. {
  783.   long ret=0;
  784.   if (hp()<=0)
  785.   {
  786.     if (state!=dead)
  787.     {
  788.       set_xacel(0);
  789.       set_fxacel(0);
  790.  
  791.       if (has_sequence(dieing))
  792.       {      
  793.     if (state!=dieing)
  794.     {
  795.       set_state(dieing);
  796.       set_xvel(0);
  797.     }
  798.       } else 
  799.       { set_xvel(0); 
  800.     set_fxvel(0);
  801.     if (has_sequence(dead))
  802.           set_state(dead); 
  803.     else return 0;
  804.       }
  805.     } 
  806.   }
  807.  
  808.   long fxv=sfxvel()+sfxacel(),fyv=sfyvel()+sfyacel();
  809.   long xv=xvel()+xacel()+(fxv>>8),yv=yvel()+yacel()+(fyv>>8);
  810.  
  811.   if (xv!=xvel() || yv!=yvel())   // only store vel's if changed so we don't increase object size
  812.   {
  813.     set_xvel(xv);
  814.     set_yvel(yv);
  815.   }
  816.  
  817.   if (fxv!=sfxvel() || fyv!=sfyvel())
  818.   {
  819.     set_fxvel(fxv&0xff);
  820.     set_fyvel(fyv&0xff);
  821.   }
  822.  
  823.  
  824.   if (fxv || fyv || xv || yv)   // don't even try if there is no velocity
  825.   {
  826.     long nx=x,ny=y;
  827.     long ffx=fx()+sfxvel(),ffy=fy()+sfyvel();
  828.     long nxv=xvel()+(ffx>>8);
  829.     long nyv=yvel()+(ffy>>8);
  830.     set_fx(ffx&0xff);
  831.     set_fy(ffy&0xff);
  832.     
  833.     long old_nxv=nxv,old_nyv=nyv;
  834.     game_object *hit_object=try_move(x,y,nxv,nyv,3);   // now find out what velocity is safe to use
  835.     
  836. /*    if (get_cflag(CFLAG_STOPPABLE))
  837.     {
  838.       game_object *r=current_level->boundary_setback(exclude,x,y,nxv,nyv,1);
  839.       if (r) hit_object=r;
  840.     }*/
  841.  
  842.     x+=nxv;
  843.     y+=nyv;
  844.     if (old_nxv!=nxv || old_nyv!=nyv)
  845.     {
  846.       long lx=last_tile_hit_x,ly=last_tile_hit_y;
  847.       stop();
  848.       if (old_nxv==0)
  849.       {
  850.     if (old_nyv>0) ret|=BLOCKED_DOWN;
  851.     else if (old_nyv<0) ret|=BLOCKED_UP;
  852.       } else if (old_nyv==0)
  853.       {
  854.     if (old_nxv>0) ret|=BLOCKED_RIGHT;
  855.     else if (old_nxv<0) ret|=BLOCKED_LEFT;
  856.       } else
  857.       {
  858.     long tx=(old_nxv>0 ? 1 : -1),ty=0;
  859.     try_move(x,y,tx,ty,3);
  860.     if (!tx)     
  861.       ret|=(old_nxv>0 ? BLOCKED_RIGHT : BLOCKED_LEFT);    
  862.     else tx=0;
  863.  
  864.     ty=(old_nyv>0 ? 1 : -1);
  865.     try_move(x,y,tx,ty,3);
  866.     if (!ty)     
  867.       ret|=(old_nyv>0 ? BLOCKED_DOWN : BLOCKED_UP);
  868.     
  869.     if (!ret)
  870.       ret|=(old_nyv>0 ? BLOCKED_DOWN : BLOCKED_UP) | (old_nxv>0 ? BLOCKED_RIGHT : BLOCKED_LEFT);
  871.  
  872.       }
  873.  
  874.       void *rlist=NULL;   // return list
  875.       p_ref r1(rlist);
  876.  
  877.       if (hit_object)
  878.       {
  879.     push_onto_list(new_lisp_pointer(hit_object),rlist);
  880.     push_onto_list(l_object,rlist);
  881.       } else
  882.       {
  883.     push_onto_list(new_lisp_number(ly),rlist);
  884.     push_onto_list(new_lisp_number(lx),rlist);
  885.     push_onto_list(l_tile,rlist);
  886.       }
  887.       push_onto_list(new_lisp_number(ret),rlist);
  888.  
  889.       return rlist;
  890.     } else return true_symbol;
  891.   }
  892.   return true_symbol;
  893. }
  894.  
  895. int game_object::tick()      // returns blocked status
  896. {
  897.   int blocked=0;
  898.  
  899.   long xt=0,yt=2;
  900.   try_move(x,y-2,xt,yt,1);    // make sure we are not falling through the floor
  901.   y=y-2+yt;
  902.   
  903.   if (flags()&FLAG_JUST_BLOCKED)
  904.     set_flags(flags()-FLAG_JUST_BLOCKED);
  905.  
  906.   if (gravity() && !floating())
  907.   {
  908.     int fya;
  909.     if (yacel()>=0)
  910.       fya=sfyacel()+200;
  911.     else
  912.       fya=sfyacel()-200;
  913.  
  914.     set_yacel(yacel()+(fya>>8));
  915.     set_fyacel(fya&255);
  916.   }
  917.   
  918.   // first let's move the guy acording to his physics
  919.   long xa=xacel(),ya=yacel(),fxa=sfxacel(),fya=sfyacel();
  920.   if (xa || ya || fxa || fya)
  921.   {
  922.     int fxv=sfxvel(),fyv=sfyvel();
  923.     fxv+=fxa;  fyv+=fya;    
  924.     long xv=xvel()+xa+(fxv>>8); 
  925.     set_xvel(xvel()+xa+(fxv>>8));
  926.     set_yvel(yvel()+ya+(fyv>>8));
  927.     set_fxvel(fxv&0xff);
  928.     set_fyvel(fyv&0xff);
  929.   }
  930.   
  931.   // check to see if this advancement causes him to collide with objects
  932.   long old_vy=yvel(),old_vx=xvel();  // save the correct veloicties
  933.  
  934.   if (old_vx || old_vy)
  935.   {
  936.     int up=0;
  937.     if (yvel()<=0)  // if we are going up or a strait across check up and down
  938.     up=2;
  939.     long xv=xvel(),yv=yvel();
  940.     game_object *h=try_move(x,y,xv,yv,1|up);       // now find out what velocity is safe to use
  941.     set_xvel(xv);
  942.     set_yvel(yv);
  943.     x+=xv;
  944.     y+=yv;
  945.  
  946.     if (h && stoppable()) return BLOCKED_LEFT|BLOCKED_RIGHT;
  947.  
  948.     if (xv!=old_vx || yv!=old_vy)     // he collided with something
  949.     {          
  950.       if (gravity())                         // was he going up or down?
  951.       {                           
  952.     long fall_xv=0,old_fall_vy,fall_vy;
  953.     old_fall_vy=fall_vy=old_vy-yvel();             // make sure he gets all of his yvel
  954.     try_move(x,y,fall_xv,fall_vy,1|up);
  955.     if (old_vy>0 && fall_vy<old_fall_vy)       // he was trying to fall, but he hit the ground
  956.     {
  957.       if (old_vy>0)    
  958.       {
  959.         blocked|=BLOCKED_DOWN;
  960.         
  961.         if (!xvel() && has_sequence(end_run_jump))      
  962.         {
  963.           set_xvel(old_vx);
  964.           set_state(end_run_jump);
  965.         }
  966.         else set_state(stopped);      
  967.       }
  968.       else blocked|=BLOCKED_UP;
  969.  
  970.  
  971.       if (state==run_jump_fall)
  972.       {
  973.         if (has_sequence(running))
  974.         set_state(running);
  975.         else
  976.         {
  977.           stop_x();
  978.           set_state(stopped);
  979.         }
  980.       }
  981.       else
  982.       {
  983.         set_yacel(0);
  984.         set_fyacel(0);
  985.         set_yvel(0);
  986.         set_fyvel(0);
  987.         set_gravity(0);
  988.       }
  989.  
  990.     } else 
  991.     {
  992.       if (old_vy!=0)
  993.       {
  994.         long testx=old_vx<0 ? -1 : 1,testy=0;    // see if we were stopped left/right
  995.                                                      // or just up down
  996.         try_move(x,y,testx,testy,1|up);
  997.         if (testx==0)                           // blocked left/right, set flag
  998.         {
  999.           if (old_vx<0)
  1000.             blocked|=BLOCKED_LEFT;
  1001.           else
  1002.             blocked|=BLOCKED_RIGHT;
  1003.         }
  1004.         else if (old_vy<0)
  1005.           blocked|=BLOCKED_UP;
  1006.         else if (old_vy>0)
  1007.           blocked|=BLOCKED_DOWN;
  1008.  
  1009.       } else if (old_vx<0)   // we can skip left/right test because player wasn't moving up/down
  1010.             blocked|=BLOCKED_LEFT;
  1011.       else
  1012.             blocked|=BLOCKED_RIGHT;
  1013.  
  1014.       set_xvel(0);
  1015.       set_fxvel(0);
  1016.       if (old_vy<0 && fall_vy>0)        
  1017.       {
  1018.         set_yvel(yvel()+fall_vy);
  1019.       } else set_yvel(yvel()+fall_vy);
  1020.     }      
  1021.     y+=fall_vy;            
  1022.       }    
  1023.       else                  // see if we can make him 'climb' the hill
  1024.       {
  1025.     long ox=x,oy=y;       // rember orginal position in case climb doesn't work
  1026.  
  1027.     long climb_xvel=0,climb_yvel=-5;        // try to move up one pixel to step over the 
  1028.     try_move(x,y,climb_xvel,climb_yvel,3);  // jutting polygon line
  1029.     y+=climb_yvel;
  1030.  
  1031.     climb_xvel=old_vx-xvel();
  1032.     climb_yvel=-(abs(climb_xvel));        // now try 45 degree slope
  1033.     try_move(x,y,climb_xvel,climb_yvel,3);
  1034.  
  1035.     if (abs(climb_xvel)>0)  // see if he got further by climbing
  1036.     {
  1037.       blocked=blocked&(~(BLOCKED_LEFT|BLOCKED_RIGHT));
  1038.       x+=climb_xvel;
  1039.       y+=climb_yvel;
  1040.  
  1041.       set_xvel(xvel()+climb_xvel);
  1042.       set_yvel(0);          
  1043.       set_fyvel(0);
  1044.       
  1045.       // now put him back on the ground          
  1046.       climb_yvel=abs(climb_xvel)+5;               // plus one to put him back on the ground
  1047.       climb_xvel=0;
  1048.       try_move(x,y,climb_xvel,climb_yvel,1);
  1049.       if (climb_yvel)
  1050.           y+=climb_yvel;
  1051.     }
  1052.     else             
  1053.     {    
  1054.       if (old_vx<0)
  1055.           blocked|=BLOCKED_LEFT;
  1056.       else
  1057.           blocked|=BLOCKED_RIGHT;
  1058.       set_state(stopped);      // nope, musta hit a wall, stop the poor fella
  1059.       x=ox;
  1060.       y=oy;    
  1061.     }
  1062.     
  1063.       }
  1064.       
  1065.       if (xvel()!=old_vx && state!=run_jump_fall && state!=end_run_jump)
  1066.       {
  1067.     set_xacel(0); 
  1068.     set_fxacel(0);
  1069.       }
  1070.     }
  1071.   }
  1072.      
  1073.   if (yacel()==0 && !gravity())       // he is not falling, make sure he can't
  1074.   {
  1075.     long nvx=0,nvy=yvel()+12;  // check three pixels below for ground
  1076.     try_move(x,y,nvx,nvy,1); 
  1077.     if (nvy>11)                    // if he falls more than 2 pixels, then he falls
  1078.     {
  1079.       if (state!=run_jump_fall)      // make him fall
  1080.       {       
  1081.         if (has_sequence(run_jump_fall))
  1082.           set_state(run_jump_fall);
  1083.         set_gravity(1);
  1084.       }
  1085.     } else if (nvy)   // if he fells less than 3 pixels then let him descend 'hills'
  1086.     {      
  1087.       y+=nvy;
  1088.       blocked|=BLOCKED_DOWN;      
  1089.     }    
  1090.   }
  1091.   return blocked;
  1092. }
  1093.  
  1094. void game_object::defaults()
  1095. {
  1096.   set_state(state);
  1097.   if (otype!=0xffff)
  1098.   {
  1099.     int s=get_ability(otype,start_hp);
  1100.     if (s!=default_simple.hp())
  1101.       set_hp(s);
  1102.   }
  1103. }
  1104.  
  1105. void game_object::frame_advance()
  1106. {
  1107.   int ad=current_sequence()->get_advance(current_frame);
  1108.   if (ad && current_level)
  1109.   {
  1110.     long xv;
  1111.     if (direction>0) xv=ad; else xv=-ad;
  1112.     long yv=0;
  1113.     try_move(x,y,xv,yv,3);
  1114.     x+=xv;
  1115.   }   
  1116. }
  1117.  
  1118. void game_object::set_state(character_state s, int frame_direction)
  1119. {
  1120.   if (has_sequence(s))
  1121.     state=s;
  1122.   else state=stopped;
  1123.  
  1124.   current_frame=0;  
  1125.   if (frame_direction!=1)
  1126.     set_frame_dir(frame_direction); 
  1127.  
  1128.   frame_advance();
  1129. }
  1130.  
  1131.  
  1132. game_object *create(int type, long x, long y, int skip_constructor, int aitype)
  1133. {
  1134.   game_object *g=new game_object(type,skip_constructor);
  1135.   g->x=x; g->y=y; g->last_x=x; g->last_y=y;
  1136.   if (aitype)
  1137.     g->set_aitype(aitype);
  1138.   if (figures[type]->get_fun(OFUN_CONSTRUCTOR) && !skip_constructor)
  1139.   {
  1140.     game_object *o=current_object;
  1141.     current_object=g;    
  1142.  
  1143.     void *m=mark_heap(TMP_SPACE);
  1144.  
  1145.     time_marker *prof1;
  1146.     if (profiling())
  1147.       prof1=new time_marker;
  1148.  
  1149.     eval_function((lisp_symbol *)figures[type]->get_fun(OFUN_CONSTRUCTOR),NULL);
  1150.     if (profiling())
  1151.     {
  1152.       time_marker now;
  1153.       profile_add_time(type,now.diff_time(prof1));
  1154.       delete prof1;
  1155.     }
  1156.  
  1157.  
  1158.  
  1159.     restore_heap(m,TMP_SPACE);
  1160.  
  1161.     current_object=o;
  1162.   }
  1163.   return g;
  1164. }
  1165.  
  1166. int base_size()
  1167. {
  1168.   return 1+  
  1169.          1*8+
  1170.      2*5+
  1171.      4*7;
  1172. }
  1173.  
  1174. int game_object::size()
  1175. {
  1176.   return base_size();
  1177. }
  1178.  
  1179.  
  1180.  
  1181. int game_object::move(int cx, int cy, int button)
  1182. {  
  1183.   int ret=0;
  1184.  
  1185.   if (figures[otype]->get_fun(OFUN_MOVER))      // is a lisp move function defined?
  1186.   {
  1187.     void *lcx,*lcy,*lb;
  1188.  
  1189.     game_object *o=current_object;
  1190.     current_object=this;
  1191.  
  1192.  
  1193.     // make a list of the parameters, and call the lisp function
  1194.     lcx=new_cons_cell();
  1195.     l_ptr_stack.push(&lcx);
  1196.     ((cons_cell *)lcx)->car=new_lisp_number(cx);
  1197.  
  1198.     lcy=new_cons_cell();
  1199.     l_ptr_stack.push(&lcy);
  1200.     ((cons_cell *)lcy)->car=new_lisp_number(cy);
  1201.  
  1202.     lb=new_cons_cell();
  1203.     l_ptr_stack.push(&lb);
  1204.     ((cons_cell *)lb)->car=new_lisp_number(button);
  1205.  
  1206.  
  1207.     ((cons_cell *)lcx)->cdr=lcy;
  1208.     ((cons_cell *)lcy)->cdr=lb;
  1209.  
  1210.     void *m=mark_heap(TMP_SPACE);
  1211.  
  1212.     time_marker *prof1;
  1213.     if (profiling())
  1214.       prof1=new time_marker;
  1215.  
  1216.     void *r=eval_function((lisp_symbol *)figures[otype]->get_fun(OFUN_MOVER),
  1217.               (void *)lcx);
  1218.     if (profiling())
  1219.     {
  1220.       time_marker now;
  1221.       profile_add_time(this->otype,now.diff_time(prof1));
  1222.       delete prof1;
  1223.     }
  1224.  
  1225.     restore_heap(m,TMP_SPACE);
  1226.  
  1227.     l_ptr_stack.pop(3);
  1228.     if (item_type(r)!=L_NUMBER)
  1229.     {
  1230.       lprint(r);
  1231.       lbreak("Object %s did not return a number from it's mover function!\n"
  1232.          "It should return a number to indicate it's blocked status to the\n"
  1233.          "ai function.",object_names[otype]);    
  1234.     }
  1235.     ret|=lnumber_value(r);
  1236.     current_object=o;
  1237.   }
  1238.   else ret|=mover(cx,cy,button);    
  1239.  
  1240.   return ret;
  1241. }
  1242.  
  1243. int game_object::mover(int cx, int cy, int button)  // return false if the route is blocked
  1244. {
  1245.   if (hp()<=0) 
  1246.     return tick();
  1247.  
  1248.   if (flinch_state(state))                    // flinching? don't move
  1249.     cx=cy=button=0;
  1250.     
  1251.  
  1252.   if (cx)          // x movement suggested?
  1253.   {      
  1254.     if (state==stopped)   // see if started moving
  1255.     {   
  1256.       if (has_sequence(running))
  1257.       {
  1258.     if (cx>0)
  1259.     {
  1260.       direction=1;
  1261.           set_xvel(get_ability(type(),run_top_speed));
  1262.     }
  1263.     else
  1264.     {
  1265.       direction=-1;
  1266.       set_xacel(-get_ability(type(),run_top_speed));
  1267.     }
  1268.     set_state(running);
  1269.       }
  1270.     } else if (state==run_jump || state==run_jump_fall)
  1271.     {
  1272.       if (cx>0)
  1273.       {
  1274.     direction=1;
  1275.     set_xacel(get_ability(type(),start_accel));           // set the appropriate accel
  1276.       } else
  1277.       {
  1278.     direction=-1;
  1279.     set_xacel(-get_ability(type(),start_accel));           // set the appropriate accel
  1280.       }      
  1281.     }
  1282.     else 
  1283.     {
  1284.       // turn him around if he pressed the other way, he is not walking so a fast turn
  1285.       // is needed, don't go through the turn sequence
  1286.       if ((cx>0  && direction<0) || (cx<0 && direction>0))
  1287.         direction=-direction;      
  1288.     } 
  1289.   }         // not pressing left or right, so slow down or stop
  1290.   else if (!gravity() && state!=start_run_jump)
  1291.   {    
  1292.     long stop_acel;
  1293.     if (xvel()<0)                                    // he was going left
  1294.     {
  1295.       stop_acel=get_ability(type(),stop_accel);    // find out how fast he can slow down
  1296.       if (xvel()+stop_acel>=0)                       // if this acceleration is enough to stop him
  1297.       {
  1298.     stop_x();
  1299.     if (!gravity())    
  1300.       set_state(stopped);      
  1301.       } else { set_xacel(stop_acel); }
  1302.     } else if (xvel()>0)
  1303.     {
  1304.       stop_acel=-get_ability(type(),stop_accel);
  1305.       if (xvel()+stop_acel<=0)
  1306.       {
  1307.     stop_x();
  1308.     if (!gravity())
  1309.       set_state(stopped);
  1310.       } else set_xacel(stop_acel);
  1311.     } else if (!gravity())                // don't stop in the air
  1312.     { 
  1313.       set_xacel(0);
  1314.       set_fxacel(0);
  1315.       // Check to see if we should go to stop state 
  1316.       if (state==running)
  1317.         set_state(stopped);
  1318.     }   
  1319.   }    
  1320.   
  1321.  
  1322. /*  if (state==still_jump || state==still_jump_fall || state==end_still_jump)
  1323.   {
  1324.     set_xacel(0);
  1325.     set_fxacel(0);
  1326.     if (xvel()>0) set_xvel(get_ability(type(),jump_top_speed));
  1327.     else if (xvel()<0) set_xvel(-get_ability(type(),jump_top_speed));
  1328.   } else if (state==run_jump || state==run_jump_fall || state==end_run_jump)
  1329.   {
  1330.     set_xacel(0);
  1331.     set_fxacel(0);
  1332.     if (xvel()>0) set_xvel(get_ability(type(),jump_top_speed));
  1333.     else if (xvel()<0) set_xvel(-get_ability(type(),jump_top_speed));
  1334.   } */
  1335.   
  1336.   // see if the user said to jump
  1337.   if (cy<0 && !floating() && !gravity())
  1338.   {
  1339.     set_gravity(1);      
  1340.     set_yvel(get_ability(type(),jump_yvel));
  1341. //    if (cx && has_sequence(run_jump))
  1342.       set_state(run_jump);
  1343.     if (xvel()!=0)
  1344.       if (direction>0)
  1345.         set_xvel(get_ability(type(),jump_top_speed));
  1346.       else
  1347.         set_xvel(-get_ability(type(),jump_top_speed));
  1348.     set_xacel(0);
  1349.  
  1350.  
  1351. /*    if (state==stopped)  
  1352.     {
  1353.       if (cx && has_sequence(start_run_jump))
  1354.         set_state(start_run_jump);
  1355.       else if (has_sequence(start_still_jump))
  1356.         set_state(start_still_jump);                
  1357.       else 
  1358.       {
  1359.  
  1360.       }
  1361.     }
  1362.     else if (state==running && has_sequence(run_jump))
  1363.     {
  1364.       set_state(run_jump);
  1365.       set_yvel(get_ability(type(),jump_yvel));
  1366.       set_gravity(1);      
  1367.     }    
  1368.     else if (state==walking || state==turn_around)  // if walking check to see if has a
  1369.     {
  1370.       if (has_sequence(start_still_jump))
  1371.         set_state(start_still_jump);    
  1372.       else
  1373.       {
  1374.         set_yvel(get_ability(type(),jump_yvel));
  1375.         set_gravity(1);      
  1376.         if (has_sequence(run_jump))
  1377.           set_state(run_jump);
  1378.       }
  1379.     }    */
  1380.   }
  1381.  
  1382.  
  1383.  
  1384.   if (state==run_jump && yvel()>0)
  1385.     set_state(run_jump_fall);
  1386.     
  1387.  
  1388.  
  1389. //  if (state!=end_still_jump && state!=end_run_jump)
  1390.   {    
  1391.     if (cx>0)
  1392.       set_xacel(get_ability(type(),start_accel));
  1393.     else if (cx<0)
  1394.       set_xacel(-get_ability(type(),start_accel));
  1395.   }  
  1396.   
  1397.   // make sure they are not going faster than their maximum speed
  1398.   int top_speed;
  1399.   if (state==stopped || state==end_run_jump)
  1400.     top_speed=get_ability(type(),walk_top_speed);
  1401.   else if (state==running)
  1402.     top_speed=get_ability(type(),run_top_speed);    
  1403.   else if (state==run_jump || state==run_jump_fall || state==start_run_jump)
  1404.   {
  1405.     top_speed=get_ability(type(),jump_top_speed);      
  1406.     if (!cx) top_speed=0;
  1407.   }
  1408.   else top_speed=1000;
  1409.     
  1410.       
  1411.   if (abs(xvel()+xacel())>top_speed)
  1412.   {    
  1413.     if (xacel()<0) set_xacel(-top_speed-xvel());
  1414.     else set_xacel(top_speed-xvel());
  1415.   }  
  1416.     
  1417.   character_state old_state=state;
  1418.   int old_frame=current_frame;    
  1419.   int tick_stat=tick();
  1420.  
  1421.   // if he started to jump and slammed into a wall then make sure he stays in this state
  1422.   // so he can finish the jump
  1423.   if (!tick_stat && (old_state==start_run_jump))
  1424.   {
  1425.     set_state(old_state);
  1426.     current_frame=old_frame;
  1427.     next_picture();    
  1428.   }
  1429.     
  1430.   return tick_stat;
  1431.     
  1432. }
  1433.  
  1434.  
  1435.  
  1436.  
  1437. game_object *game_object::bmove(int &whit, game_object *exclude)
  1438. {
  1439.  
  1440.   // first let's move the guy acording to his physics
  1441.   long xa=xacel(),ya=yacel(),fxa=sfxacel(),fya=sfyacel();
  1442.   if (xa || ya || fxa || fya)
  1443.   {
  1444.     int fxv=sfxvel(),fyv=sfyvel();
  1445.     fxv+=fxa;  fyv+=fya;    
  1446.     long xv=xvel()+xa+(fxv>>8); 
  1447.     set_xvel(xvel()+xa+(fxv>>8));
  1448.     set_yvel(yvel()+ya+(fyv>>8));
  1449.     set_fxvel(fxv&0xff);
  1450.     set_fyvel(fyv&0xff);
  1451.   }
  1452.   
  1453.   long ox2,oy2;
  1454.  
  1455.   long nx=x+xvel(),nfx=fx()+fxvel(),ny=y+yvel(),nfy=fy()+fyvel();
  1456.   nx+=nfx>>8;
  1457.   ny+=nfy>>8;
  1458.  
  1459.  
  1460.   // check to see if this advancement causes him to collide with objects
  1461.   ox2=nx;
  1462.   oy2=ny;  // save the correct veloicties
  1463.   
  1464.   current_level->foreground_intersect(x,y,nx,ny);  // first see how far we can travel
  1465.   game_object *ret=current_level->all_boundary_setback(exclude,x,y,nx,ny);
  1466.   x=nx;
  1467.   y=ny;
  1468.   set_fx(nfx&0xff);
  1469.   set_fy(nfy&0xff);
  1470.   if (ret)
  1471.   {
  1472.     if (!ret->hurtable())   // object is not hurtable, return as if hit wall.
  1473.     { whit=1;
  1474.       return NULL;
  1475.     } else
  1476.     return ret;
  1477.   }
  1478.   else
  1479.   {
  1480.     whit=(nx!=ox2 || ny!=oy2);
  1481.     return NULL;
  1482.   }
  1483. }
  1484.  
  1485.  
  1486.  
  1487. int object_to_number_in_list(game_object *who, object_node *list)
  1488. {
  1489.   int x=1;
  1490.   while (list) 
  1491.   { 
  1492.     if (who==list->me) return x; 
  1493.     else list=list->next;
  1494.     x++;
  1495.   }
  1496.   return 0;
  1497. }
  1498.  
  1499. game_object *number_to_object_in_list(long x, object_node *list)
  1500. {
  1501.   if (!x) return NULL; x--;
  1502.   while (x && list) { list=list->next; x--; }
  1503.   if (list) return list->me;
  1504.   else return NULL;
  1505. }
  1506.  
  1507.  
  1508. void delete_object_list(object_node *first)
  1509. {
  1510.   while (first)
  1511.   {
  1512.     object_node *n=first;
  1513.     first=first->next;
  1514.     delete n;
  1515.   }
  1516. }
  1517.  
  1518.  
  1519. long object_list_length(object_node *list)
  1520. {
  1521.   long x=0;
  1522.   while (list) { list=list->next; x++; }
  1523.   return x;
  1524.   
  1525. }
  1526.  
  1527.  
  1528.  
  1529. game_object::game_object(int Type, int load) 
  1530.   if (Type<0xffff)
  1531.   {
  1532.     int t=figures[Type]->tv;
  1533.     if (t)
  1534.     {
  1535.       lvars=(long *)jmalloc(t*4,"object vars");
  1536.       memset(lvars,0,t*4);
  1537.     }
  1538.     else lvars=NULL;
  1539.   } else lvars=NULL;
  1540.  
  1541.   otype=Type; 
  1542.   if (!load) defaults(); 
  1543. }
  1544.  
  1545.  
  1546. int game_object::reduced_state()
  1547. {
  1548.   long x=0;
  1549.   for (int i=0;i<figures[otype]->ts;i++)
  1550.   {
  1551.     if (i==state) return x;
  1552.       else
  1553.     if (figures[otype]->seq[i]) x++;
  1554.   }
  1555.   return 0;
  1556. }
  1557.  
  1558.  
  1559. void game_object::change_aitype(int new_type)
  1560. {
  1561.   set_aitype(new_type);
  1562.   if (otype<0xffff)
  1563.   {
  1564.     void *f=figures[otype]->get_fun(OFUN_CHANGE_TYPE);  
  1565.     if (f) 
  1566.     {
  1567.       game_object *o=current_object;
  1568.       current_object=(game_object *)this;
  1569.  
  1570.       time_marker *prof1;
  1571.       if (profiling())
  1572.         prof1=new time_marker;
  1573.  
  1574.       eval_user_fun((lisp_symbol *)f,NULL);
  1575.  
  1576.       if (profiling())
  1577.       {
  1578.     time_marker now;
  1579.     profile_add_time(this->otype,now.diff_time(prof1));
  1580.     delete prof1;
  1581.       }
  1582.  
  1583.  
  1584.       current_object=o;
  1585.     }
  1586.   }
  1587. }
  1588.  
  1589.  
  1590. void game_object::change_type(int new_type)
  1591. {
  1592.   if (lvars) jfree(lvars);     // free old variable
  1593.  
  1594.   if (otype<0xffff)
  1595.   {
  1596.     int t=figures[new_type]->tv;
  1597.     if (t)
  1598.     {
  1599.       lvars=(long *)jmalloc(t*4,"object vars");
  1600.       memset(lvars,0,t*4);
  1601.     }
  1602.     else lvars=NULL;
  1603.   } else return;
  1604.   otype=new_type;
  1605.  
  1606.   if (figures[new_type]->get_fun(OFUN_CONSTRUCTOR))
  1607.   {
  1608.     game_object *o=current_object;
  1609.     current_object=this;    
  1610.  
  1611.     void *m=mark_heap(TMP_SPACE);
  1612.  
  1613.     time_marker *prof1;
  1614.     if (profiling())
  1615.       prof1=new time_marker;
  1616.  
  1617.     eval_function((lisp_symbol *)figures[new_type]->get_fun(OFUN_CONSTRUCTOR),NULL);
  1618.     if (profiling())
  1619.     {
  1620.       time_marker now;
  1621.       profile_add_time(otype,now.diff_time(prof1));
  1622.       delete prof1;
  1623.     }
  1624.  
  1625.  
  1626.     restore_heap(m,TMP_SPACE);
  1627.  
  1628.     current_object=o;
  1629.   }  
  1630. }
  1631.